源码分析: JDK Future模式分析
[TOC]
一.基本概念
基本方法接口
- Executor接口:
void execute(Runnable command)方法。开启一个线程执行任务,无返回值 - ExecutorService接口:
继承自Executor接口,里面的submit方法,最终会开启一个线程执行任务,并返回Future对象,该对象中含有该线程的返回值 - Callable接口可用于创建线程,call方法会有返回值且可抛出异常
基本示意图
二.源码分析
线程通过submit提交,该线程的返回值是怎么放到Future中的?
1. submit源码 — 摘自ExecutorService的实现类AbstractExecutorService(子类有ThreadPoolExecutor)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
都调用了newTaskFor方法,task任务作为参数传入。使用前面提到的execute执行开启一个新的线程,直接返回newTaskFor方法返回的RunnableFuture
通过Future接口的get方法,可以获得真实数据。如果没有则阻塞,有则取出。看状态,第五步分析
2. newTaskFor方法1
2
3
4
5
6
7protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
这里都调用了FutureTask的不同参数的构造方法。即每个newTaskFor方法得到的RunnableFuture接口的类型为FutureTask实现类
3. FutureTask的构造方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
- FutureTask中含有Callable类型的属性
- 以Runnable接口为参数的构造方法,调用了callable方法。该方法源码已贴,即使用了适配器模式,将Runnable接口适配成Callable接口类型(即call方法调用run,且无返回值)。放入到FutureTask的Callable属性
- 以Callable接口为参数的构造方法,直接放入到FutureTask的Callable属性
4. FutureTask的run方法。看完1-3,此时构造FutureTask完毕(即封装原始task完毕),开始调用executor方法,以FutureTask作为任务参数,开启新线程执行其中的run方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
其中调用call方法即执行了原始的任务。其他代码即是封装处理的部分,将返回的参数信息放到Future的result中
5. Future的get方法。获得真实数据1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
for (;;) {
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
else if (q == null)
q = new WaitNode();
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos);
}
else
LockSupport.park(this);
}
}